/*
 * $Id: AscTar.java,v 1.3 2009/07/24 18:28:04 oliver Exp $
 *
 * Copyright (C) 2006 General Electric Company. All Rights Reserved.
 *
 * This software is the confidential and proprietary information of the General
 * Electric Company (GE). You shall not disclose this software and shall use it
 * only in accordance with the terms of the license agreement you entered into
 * with GE.
 *
 * GE MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
 * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 * NON-INFRINGEMENT. GE SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING, OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES.
 */

/*
 ** Authored by Timothy Gerard Endres
 ** <mailto:time@ice.com>  <http://www.ice.com>
 ** 
 ** This work has been placed into the public domain.
 ** You may use this work in any way and for any purpose you wish.
 **
 ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
 ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
 ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
 ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
 ** REDISTRIBUTION OF THIS SOFTWARE. 
 ** 
 */

package com.ge.healthcare.autosc.common.util.tar;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Vector;
import java.util.zip.GZIPInputStream;

/**
 * The AscTar class implements a weak reproduction of the traditional UNIX
 * AscTar command. It currently supports creating, listing, and extracting from
 * archives. It also supports GZIP-ed archives with the '-z' flag. See the usage
 * (-? or --usage) for option details.
 * 
 * @version $Revision: 1.3 $
 * @author Timothy Gerard Endres, <a
 *         href="mailto:time@ice.com">time@ice.com</a>.
 * @see TarArchive
 */

public class AscTar implements TarProgressDisplay {
	protected static final String statusPrefix = "ASCTAR";
	public static final int TAR_ONLY = 0;
	public static final int GZIP_TAR = 1;
	public static final int GZIP_ONLY = 2;
	private int blockSize = 0;
	private File archiveName = null;
	private int compressed = TAR_ONLY;
	private Vector<String> tableContents = new Vector<String>();
	protected String lastStatusMessage = "Constructed but not initialized";

	/**
	 * Constructor
	 */
	public AscTar(File name) {
		this(name, TAR_ONLY);
	}

	public AscTar(File name, int gzip) {
		this.blockSize = TarBuffer.DEFAULT_BLKSIZE;
		this.archiveName = name;
		this.compressed = gzip;
	}

	/**
	 * Returns last status as String
	 * 
	 * @return String
	 */
	public String getLastStatusMessage() {
		return lastStatusMessage;
	}

	/**
	 * Establishes the default userName with the 'user.name' property.
	 */
	public TarArchive open(File archiveName) {
		InputStream inStream = null;
		TarArchive archive = null;
		tableContents.clear();

		if (archiveName != null) {
			try {
				inStream = new FileInputStream(archiveName);
			} catch (IOException ex) {
				inStream = null;
				lastStatusMessage = statusPrefix
						+ "0001 - Failed to open file: "
						+ archiveName.getPath() + "  IOException: "
						+ ex.getMessage();
			}
		}

		if (inStream != null) {
			if (this.compressed == GZIP_TAR) {
				try {
					inStream = new GZIPInputStream(inStream);
				} catch (IOException ex) {
					inStream = null;
					lastStatusMessage = statusPrefix
							+ "0001 - Failed to open file(GZIP): "
							+ archiveName.getPath() + "  IOException: "
							+ ex.getMessage();
				}
			}

			archive = new TarArchive(inStream, this.blockSize);
			if (archive != null) {
				archive.setDebug(false);
				archive.setVerbose(false);
				archive.setTarProgressDisplay(this);
				archive.setKeepOldFiles(false);
				archive.setAsciiTranslation(false);
			}
		}
		return archive;
	}

	/**
	 * List an archive.
	 */
	public Enumeration<String> list() {
		TarArchive archive = open(archiveName);

		if (archive == null) {
			return null;
		}
		try {
			archive.listContents();
		} catch (InvalidHeaderException ex) {
			lastStatusMessage = statusPrefix
					+ "0010 - Failed to read archive: " + archiveName.getPath()
					+ "  InvalidHeaderException: " + ex.getMessage();
		} catch (IOException ex) {
			lastStatusMessage = statusPrefix
					+ "0011 - Failed to read archive: " + archiveName.getPath()
					+ "  IOException: " + ex.getMessage();
		}
		close(archive);

		return getFileList();
	}

	public Enumeration<String> extract(File destDir) {

		if (compressed == GZIP_ONLY) {
			File oFile = null;
			GZIPInputStream br = null;
			FileOutputStream out = null;
			try {
				oFile = File.createTempFile("gzip", ".ungz", destDir);
				br = new GZIPInputStream(new FileInputStream(this.archiveName));
				out = new FileOutputStream(oFile);

				byte[] rdbuf = new byte[32 * 1024];
				int numRead = br.read(rdbuf, 0, (32 * 1024));
				for (; numRead > 0; numRead = br.read(rdbuf, 0, (32 * 1024))) {
					out.write(rdbuf, 0, numRead);
				}
			} catch (Exception e) {
				lastStatusMessage = statusPrefix
						+ "0030 - Failed reading GZIP_ONLY file: "
						+ this.archiveName + " error: " + e.getMessage();
			}
			try {
				if (br != null)
					br.close();
			} catch (Exception e) {
				lastStatusMessage = statusPrefix
						+ "0032 - Failed closing GZIP_ONLY file: "
						+ this.archiveName + " error: " + e.getMessage();
			}
			if (out != null) {
				try {
					out.close();
				} catch (Exception e) {
					lastStatusMessage = statusPrefix
							+ "0033 - Failed closing GZIP_ONLY file: "
							+ oFile.getPath() + " error: " + e.getMessage();
				}
			}
			if (oFile != null) {
				tableContents.addElement(oFile.getPath());
			}
			return tableContents.elements();
		}

		TarArchive archive = open(archiveName);

		if (!destDir.exists()) {
			if (!destDir.mkdirs()) {
				lastStatusMessage = statusPrefix
						+ "0020 - Failed to create directory: "
						+ destDir.getPath();
				destDir = null;
			}
		}

		if ((destDir != null) && (archive != null)) {
			try {
				archive.extractContents(destDir);
			} catch (InvalidHeaderException ex) {
				lastStatusMessage = statusPrefix + "0021 - Failed to extract: "
						+ "  InvalidHeaderException: " + ex.getMessage();
			} catch (IOException ex) {
				lastStatusMessage = statusPrefix + "0022 - Failed to extract: "
						+ "  IOException: " + ex.getMessage();
			}
		}
		close(archive);

		return getFileList();
	}

	public void close(TarArchive archive) {
		if (archive != null) // CLOSE ARCHIVE
		{
			try {
				archive.closeArchive();
			} catch (IOException ex) {
			}
		}
	}

	// I N T E R F A C E TarProgressDisplay

	/**
	 * Display progress information by printing it to System.out.
	 */
	public void showTarProgressMessage(String msg) {
		System.out.println(msg);
	}

	/**
	 * Callback as archive entries are processed
	 */
	public void processedEntryName(String msg) {
		tableContents.addElement(msg);
	}

	/**
	 * Get list of files processed
	 */
	private Enumeration<String> getFileList() {
		return tableContents.elements();
	}

}
